package org.boun.swe.ARCEONE.Utility;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Type;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.HTTP;
import org.boun.swe.ARCEONE.Static.Constants;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.google.gson.Gson;

import android.content.Context;
import android.os.AsyncTask;

public class JSONManager {
	private AsyncTaskListener asyncTaskListener;
    private DefaultHttpClient httpClient;
    private HttpGet getRequest;
    private HttpPost postRequest;
    
    public JSONManager(Context context){
    	asyncTaskListener = (AsyncTaskListener)context;
    	httpClient = new DefaultHttpClient();
    	httpClient.getParams().setParameter(ClientPNames.HANDLE_REDIRECTS, false);
    }
    
	public Object GetJSONData(String getURL, Type type){
		InputStream inputStream = retrieveStream(getURL);
		
		if(inputStream == null)
			return null;
		
		Reader reader = new InputStreamReader(inputStream);
    	return new Gson().fromJson(reader, type);
	}
    
	public void GetJSONDataAsync(String getURL, Type type){
		AsyncTask<Object, Void, Object> asyncAuthentication = new AsyncTask<Object, Void, Object>() {
			@Override
			protected Object doInBackground(Object... params) {
				InputStream inputStream = retrieveStream((String)params[0]);
				
				if(inputStream == null)
					return null;
				
				Reader reader = new InputStreamReader(inputStream);
		    	return new Gson().fromJson(reader, (Type)params[1]);
			}

		    protected void onPostExecute(Object object) {
		    	asyncTaskListener.onJSONGetCompleted(object);
		    }
		};
		asyncAuthentication.execute(getURL, type);
	}
	
	public String GetReverseGeocodingResult(double latitude, double longitude){
    	try {
            String readLine = "";
            String responseData = "";
            
			InputStream inputStream = retrieveStream(String.format(Constants.REVERSE_GEOCODING_URL, latitude, longitude));
    		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
    		
            while((readLine = bufferedReader.readLine()) != null)
            	responseData += readLine;
            
            JSONArray reverseGeocodingResultsArray = new JSONObject(responseData).getJSONArray("results");
            JSONArray reverseGeocodingAddressComponentsArray = reverseGeocodingResultsArray.getJSONObject(0).getJSONArray("address_components");
            return reverseGeocodingAddressComponentsArray.getJSONObject(2).getString("long_name") + ", " +
            		reverseGeocodingAddressComponentsArray.getJSONObject(3).getString("long_name");
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (JSONException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public void GetReverseGeocodingResultAsync(final double latitude, final double longitude){
		AsyncTask<Void, Void, String> asyncAuthentication = new AsyncTask<Void, Void, String>() {
			@Override
			protected String doInBackground(Void... params) {
		    	try {
		            String readLine = "";
		            String responseData = "";
		            
					InputStream inputStream = retrieveStream(String.format(Constants.REVERSE_GEOCODING_URL, latitude, longitude));
		    		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
		    		
		            while((readLine = bufferedReader.readLine()) != null)
		            	responseData += readLine;
		            
		            JSONArray reverseGeocodingResultsArray = new JSONObject(responseData).getJSONArray("results");
		            JSONArray reverseGeocodingAddressComponentsArray = reverseGeocodingResultsArray.getJSONObject(0).getJSONArray("address_components");
		            return reverseGeocodingAddressComponentsArray.getJSONObject(2).getString("long_name") + ", " +
		            		reverseGeocodingAddressComponentsArray.getJSONObject(3).getString("long_name");
				} catch (ClientProtocolException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				} catch (JSONException e) {
					e.printStackTrace();
				}
				return null;
			}

		    protected void onPostExecute(String address) {
		    	asyncTaskListener.onReverseGeocodingCompleted(address);
		    }
		};
		asyncAuthentication.execute();
	}
    
    private InputStream retrieveStream(String url) {
    	try {
			getRequest = new HttpGet(new URI(url));
			HttpResponse getResponse = httpClient.execute(getRequest);
            if (getResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK)
                return getResponse.getEntity().getContent();
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
        return null;  
     }
    
	public List<Object> PostJSONData(String postURL, List<NameValuePair> nameValuePair){
		List<Object> postResult = new ArrayList<Object>();
        try {
			postRequest = new HttpPost(postURL);
			if(nameValuePair != null)
				postRequest.setEntity(new UrlEncodedFormEntity(nameValuePair, HTTP.UTF_8));
			HttpResponse postResponse = httpClient.execute(postRequest);

			if(postResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
				if(postURL.equals(Constants.POST_LOGIN)){
					String location = postResponse.getFirstHeader("Location").getValue();
					postResult.add(location.substring(location.length() - 10) != "error=true");
					postResult.add(postResponse.getFirstHeader("Set-Cookie").getElements()[0].getValue());
				}
				else
					postResult.add(true);
			}
			else
				postResult.add(false);
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
    	return postResult;
    }
}
